/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			PageMdl.h
  \date			July 2011
  \author		TNick

  \brief		Contains the definition for PageMdl class


 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @n
 Please read ReadMe.txt and Licence.txt in root folder @n
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @n

*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
#ifndef __PAGEMDL_INC__
#define __PAGEMDL_INC__
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

class		PlgEnvel;

#include    <QDebug>
#include    <QMutex>

#include    <generic/cc_l2dn.h>
#include    <data_store/pagedata.h>

#include	<QAbstractItemModel>


/*  INCLUDES    ============================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */

//#define LOCK_MUTEX_LOCK     qDebug() << "lock in " << __FUNCTION__ ; lock()
//#define MUTEX_UNLOCK_MUTEX  qDebug() << "unlock in " << __FUNCTION__ ; unlock()
#define LOCK_MUTEX_LOCK     lock()
#define MUTEX_UNLOCK_MUTEX  unlock()

/// the model that may be used to display pages
/**
  * The source for this model is stored by the MainWindow unique instance
  */
class PageMdl : public QAbstractItemModel
{
	Q_OBJECT

	//
	//
	//
	//
	/*  DEFINITIONS    ----------------------------------------------------- */

public:

	/// assigns a numeric value for each display mode
	enum        DisplMode   {
		ALL = 0,        /**< all elements are shown */
		FILTERED,       /**< only the elements that passed the filter */
		UNFILTERED,     /**< only the elements that did not passed the filter */

		MAXVAL

	};


	/*  DEFINITIONS    ===================================================== */
	//
	//
	//
	//
	/*  DATA    ------------------------------------------------------------ */

private:

    /// what items are currently shown (all, filtered or inverse filtered)
	DisplMode               dmd;

	/// number of filtered in items
	int                     filt_in_cnt;

	/// number of filtered out items
	int                     filt_out_cnt;



	/** @name CC_HDL2DN exposed     */
	//@{

	/// linked list of kids
	CC_HDL2DN               pages_header;

	//@}




	/* following two pointers indicate the last member in the chain */

	/// chain of pages that passed the filter
	PageData *              p_in_filter;

	/// chain of pages that did not passed the filter
	PageData *              p_out_filter;





	/// locks the access to pages chain
	QMutex                  page_mutex;

	/*  DATA    ============================================================ */
	//
	//
	//
	//
	/*  FUNCTIONS    ------------------------------------------------------- */


public slots:
    /// adds a new page in global chain
    void            appendNewPage           (PageData * p_new);




public:

	/// constructor
	explicit			PageMdl				(
		QObject		*parent = 0		/**< optional parent object*/
		);


	/// destructor;
	virtual				~PageMdl		(void);


    /// block the acces for others to internal storage
	inline void         lock                (void) const
	{
		((PageMdl*)this)->page_mutex.lock();

	}


    /// unblock the acces for others to internal storage
    inline void         unlock              (void) const
	{
		((PageMdl*)this)->page_mutex.unlock();
	}



    //@{	 alow fellows to trigger change signal
	inline void			dataHasChanged(QModelIndex the_idx)
	{ emit dataChanged(the_idx, the_idx); }
	inline void			dataHasChanged(QModelIndex the_idx1, QModelIndex the_idx2)
	{ emit dataChanged(the_idx1, the_idx2); }
    //@}


    /// allow outsiders to create index objects
	inline QModelIndex	createIndex(int row, int col, void* p) const
	{ return QAbstractItemModel::createIndex(row, col, p); }


	void beginInsertRows ( const QModelIndex & parent, int first, int last )
	{ QAbstractItemModel::beginInsertRows(parent, first, last); }
	void endInsertRows (void)
	{ QAbstractItemModel::endInsertRows(); }


	/// change the way items are shown
	void            setDisplayMode          (DisplMode new_mode);
	/// tell how are items shown
	inline bool     displayMode             (void) const
	{ return dmd; }


	/// adds a page to the end of the filtered in chain
    void        appendFilterIn              (
        PageData * p_prev,  /**< if non-NULL, the new page is
        appended after this page; otherwise, the chain is iterated in order to
        find a properinsertion place */
        PageData * p_new    /**< new page to insert */
        );


	/// adds a page to the end of the filtered out chain
    void        appendFilterOut             (
        PageData * p_prev,  /**< if non-NULL, the new page is
        appended after this page; otherwise, the chain is iterated in order to
        find a properinsertion place */
        PageData * p_new    /**< new page to insert */
        );


	/// resets the chains
	void        resetChains     (void)
	{
		p_in_filter = NULL; filt_in_cnt = 0;
		p_out_filter = NULL; filt_out_cnt = 0;
	}

	/// chain of pages that passed the filter
	PageData *  filterInChain        (void)
	{ return p_in_filter; }

	/// chain of pages that did not passed the filter
	PageData *  filterOutChain       (void)
	{ return p_out_filter; }


	/// scans all the pages and assign them in one of two chains
	void        createChains         (void);


	/// returns nth item that is filtered in
	PageData *  nthFilterIn         (int i);
	/// returns nth item that is filtered out
	PageData *  nthFilterOut         (int i);


    /// delete one page from this model
    void        deletePage          (PageData* p_to_del);

    /// delete pagen filtered in from this model
    void        deleteFiltIn        (void);

    /// delete pagen filtered out from this model
    void        deleteFiltOut       (void);

    /// delete all pagess from this model
    void        deleteAll           (void);

    /// delete visible pages (all, filtered in or filtered out)
    void        deleteVisible       (void);



	/** @name QAbstractItemModel */
	//@{


	/// Returns the index of the item in the model specified by the given row, column and parent index.
	/**
 *	QAbstractItemModel implementation. @n
 *	When reimplementing this function in a subclass,
 *	call createIndex() to generate model indexes that
 *	other components can use to refer to items in your model.
 */
	QModelIndex			index				(
		int						row,
		int						column,
		const					QModelIndex & parent = QModelIndex()
		) const;
	/// Returns the parent of the model item with the given index, or QModelIndex() if it has no parent.
	/**
 *	QAbstractItemModel implementation. @n
 *	A common convention used in models that expose tree data
 *	structures is that only items in the first column have
 *	children. For that case, when reimplementing this function
 *	in a subclass the column of the returned QModelIndex would be 0.
 */
	QModelIndex		parent (
		const QModelIndex &		index
		) const
	{ Q_UNUSED(index); return QModelIndex(); }


	/// Returns the number of rows under the given parent.
	/**
 *	QAbstractItemModel implementation. @n
 *	When the parent is valid it means that rowCount is
 *	returning the number of children of parent.
 */
	int				rowCount				(
		const QModelIndex &		parent = QModelIndex()
		) const;

	/// Returns number of columns for this item
	/**
 *	QAbstractItemModel implementation. @n
 */
	virtual int		columnCount				(
		const QModelIndex &		parent = QModelIndex()
		) const
	{ Q_UNUSED(parent); return 3; }


	/// Returns the data stored under the given role for the item referred to by the index.
	/**
 *	QAbstractItemModel implementation
 */
	QVariant		data					(
		const QModelIndex & index,
		int						role = Qt::DisplayRole
		) const;

	/// Returns the item flags for the given index.
	/**
 *	QAbstractItemModel implementation. @n
 *	The base class implementation returns a combination of flags that
 *	enables the item (ItemIsEnabled) and allows it
 *	to be selected (ItemIsSelectable).
 */
	Qt::ItemFlags	flags					(
		const QModelIndex &		index
		) const;


	/// Returns the data for the given role and section in the header with the specified orientation.
	/**
 *	QAbstractItemModel implementation
 */
	QVariant		headerData				(
		int						section,
		Qt::Orientation			orientation,
		int						role = Qt::DisplayRole
		) const;

	//@}


	bool hasChildren (
		const QModelIndex & parent = QModelIndex() ) const
	{
		Q_UNUSED(parent);
		if (parent.isValid())
			return false;
		else
			return true;
	}

	/** @name CC_HDL2DN exposed     */
	//@{

	/// remove all items from this list by deleting them
	inline void			erase	(void)
	{ LOCK_MUTEX_LOCK; pages_header.erase(); MUTEX_UNLOCK_MUTEX; }

	/// get the number of items
	inline int			count	(void)
	{
		LOCK_MUTEX_LOCK;
		int i = pages_header.count();
		MUTEX_UNLOCK_MUTEX;
		return i;
	}

	/// get nth item
	inline PageData*	item	(int i)
	{
		LOCK_MUTEX_LOCK;
		PageData* it = static_cast<PageData*>(pages_header.item(i));
		MUTEX_UNLOCK_MUTEX;
		return it;
	}

	/// get first item
	inline PageData*	first	(void)
	{
		LOCK_MUTEX_LOCK;
		PageData* it = static_cast<PageData*>(pages_header.first());
		MUTEX_UNLOCK_MUTEX;
		return it;
	}

	/// get last item
	inline PageData*	last	(void)
	{
		LOCK_MUTEX_LOCK;
		PageData* it = static_cast<PageData*>(pages_header.last());
		MUTEX_UNLOCK_MUTEX;
		return it;
	}

	/// returns the index of a particular item inside this chain
	inline int          itemIndex	( const PageData* pIt)
	{
		LOCK_MUTEX_LOCK;
		int i = pages_header.itemIndex(pIt);
		MUTEX_UNLOCK_MUTEX;
		return i;
	}

	/// tell if an item is part of this chain
	inline bool         has		( const PageData* pIt)
	{
		LOCK_MUTEX_LOCK;
		bool b = pages_header.has(pIt);
		MUTEX_UNLOCK_MUTEX;
		return b;
	}

	/// append an item (insert after last)
	inline void			append	(PageData* pIt)
	{ LOCK_MUTEX_LOCK; pages_header.append(pIt); MUTEX_UNLOCK_MUTEX; }

	/// prepend an item (insert as first item)
	inline void			prepend	(PageData* pIt)
	{ LOCK_MUTEX_LOCK; pages_header.prepend(pIt); MUTEX_UNLOCK_MUTEX; }

	/// remove the item at given index
	inline void			remove	(int i)
	{ LOCK_MUTEX_LOCK; pages_header.remove(i); MUTEX_UNLOCK_MUTEX; }

	/// remove a particular item
	inline void			remove	(PageData* pIt)
	{ LOCK_MUTEX_LOCK; pages_header.remove(pIt); MUTEX_UNLOCK_MUTEX; }

	/// header is informed about an item being added
	inline void			ackAdd	(PageData* pNew)
	{ LOCK_MUTEX_LOCK; pages_header.ackAdd(pNew); MUTEX_UNLOCK_MUTEX; }

	/// header is informed about an item being deleted
	inline void			ackDel	(PageData* pNew)
	{ LOCK_MUTEX_LOCK; pages_header.ackDel(pNew); MUTEX_UNLOCK_MUTEX; }

	/// set first item
	inline void			setFirst(PageData* pNew)
	{ LOCK_MUTEX_LOCK; pages_header.setFirst(pNew); MUTEX_UNLOCK_MUTEX; }

	/// set number of items
	inline void			setCount(int iNew)
	{ LOCK_MUTEX_LOCK; pages_header.setCount(iNew); MUTEX_UNLOCK_MUTEX; }

	/// insert a item at specified index
	inline void			insert(PageData* p_new, int index)
	{ LOCK_MUTEX_LOCK; pages_header.insert(p_new, index); MUTEX_UNLOCK_MUTEX; }


	/// get the index of an element based on name
	inline int          indexFromURL		(
		const QString strToCheck, bool bCaseSens = false)
	{
		LOCK_MUTEX_LOCK;
		int i = pages_header.indexFromName(strToCheck, bCaseSens);
		MUTEX_UNLOCK_MUTEX;
		return i;
	}
	/// get the pointer to an element based on name
	inline PageData*    itemFromURL		(
		const QString strToCheck, bool bCaseSens = false)
	{
		LOCK_MUTEX_LOCK;
		PageData* it = static_cast<PageData*>
				(pages_header.itemFromName(strToCheck, bCaseSens));
		MUTEX_UNLOCK_MUTEX;
		return it;
	}

	/// tell if a string is present inside
	inline bool         hasURL		(
		const QString strToCheck, bool bCaseSens = false)
	{
		LOCK_MUTEX_LOCK;
		bool b = pages_header.hasName(strToCheck, bCaseSens);
		MUTEX_UNLOCK_MUTEX;
		return b;
	}

	//@}



	/*  FUNCTIONS    ======================================================= */
	//
	//
	//
	//

};	/*	class PageMdl	*/

/*  CLASS    =============================================================== */
//
//
//
//
#endif // __PAGEMDL_INC__
/* ------------------------------------------------------------------------- */
/* ========================================================================= */

